package im.yangqiang.android.ui.widget.chart;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

import im.yangqiang.android.ui.R;


/**
 * 坐标轴，所有统计图的基类
 * <p>
 * Created by Carlton on 2016/4/20.
 */
public class AxisView extends View
{
    /**
     * 是否调试
     */
    private final boolean DEBUG = false;
    /**
     * 横坐标
     */
    private final ArrayList<Float> mXAxis = new ArrayList<>();
    /**
     * 横坐标数据
     */
    private final ArrayList<String> mXAxisData = new ArrayList<>();
    /**
     * 纵坐标
     */
    private final ArrayList<Float> mYAxis = new ArrayList<>();
    /**
     * 纵坐标数据
     */
    private final ArrayList<String> mYAxisData = new ArrayList<>();
    /**
     * 字体宽度:AAA
     */
    private float mTextWidth;
    /**
     * 字体高度
     */
    private float mTextHeight;
    /**
     * 刻度的长度
     */
    private int mLineSize = 0;
    /**
     * X轴的每一条线段的额外大小，主要用于调整最后的落点位置
     */
    private int mXExtra = 0;
    /**
     * Y轴的每一条线段的额外大小，主要用于调整最后的落点位置
     */
    private int mYExtra = 0;
    private int mXAxisFontColor;
    private float mXAxisFontSize;
    private int mYAxisFontColor;
    private float mYAxisFontSize;
    private int mXAxisSpace;
    private int mYAxisSpace;

    public AxisView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    public AxisView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public AxisView(Context context)
    {
        super(context);
        init(context, null, 0);
    }

    private void init(Context context, AttributeSet attrs, int defStyle)
    {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AxisView, defStyle, 0);
        mXAxisFontColor = typedArray.getColor(R.styleable.AxisView_x_axis_font_color, Color.BLACK);
        mXAxisFontSize = typedArray.getDimensionPixelSize(R.styleable.AxisView_x_axis_font_size, 30);
        mXAxisSpace = typedArray.getDimensionPixelSize(R.styleable.AxisView_x_axis_space, 0);
        mYAxisFontColor = typedArray.getColor(R.styleable.AxisView_y_axis_font_color, Color.BLACK);
        mYAxisFontSize = typedArray.getDimensionPixelSize(R.styleable.AxisView_y_axis_font_size, 30);
        mYAxisSpace = typedArray.getDimensionPixelSize(R.styleable.AxisView_y_axis_space, 0);

        typedArray.recycle();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);
        mTextPaint.setAntiAlias(true);

        if (isInEditMode())
        {
            demo();
        }

        setWillNotDraw(false);
    }

    private void demo()
    {
        for (int i = 0; i < 5; ++i)
        {
            mXAxisData.add("X" + i);
            mYAxisData.add("Y" + i);
        }
    }

    /**
     * 计算X坐标
     */
    private void calculateXAxis()
    {
        if (null == mXAxisData || mXAxisData.isEmpty())
        {
            return;
        }
        mXAxis.clear();
        int count = mXAxisData.size();
        float space = (getContentRight() - getO().x) / (count - 1) + mXExtra;
        mXAxis.add(mO.x);
        for (int i = 1; i < count; ++i)
        {
            mXAxis.add(mO.x + i * space);
        }
    }

    /**
     * 计算Y坐标
     */
    private void calculateYAxis()
    {
        if (null == mYAxisData || mYAxisData.isEmpty())
        {
            return;
        }
        mYAxis.clear();
        int count = mYAxisData.size();
        float space = (mO.y - getContentTop()) / (count - 1) - mYExtra;
        mYAxis.add(mO.y);
        for (int i = 1; i < count; ++i)
        {
            mYAxis.add(mO.y - i * space);
        }
    }

    private PointF mO = new PointF();

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        calculateXAxis();
        calculateYAxis();
        super.onLayout(changed, left, top, right, bottom);
    }

    private Paint mPaint = new Paint();
    private TextPaint mTextPaint = new TextPaint();
    /**
     * 返回Y轴坐标的最大宽度
     *
     * @return
     */
    private float getMaxTextWidth()
    {
        float width = 0;
        mTextPaint.setTextSize(mYAxisFontSize);
        for (String s : getYAxisData())
        {
            float textWidth = getTextWidth(mTextPaint, s);
            width = textWidth > width ? textWidth : width;
        }
        return width;
    }
    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        doDraw(canvas);
    }

    private void doDraw(Canvas canvas)
    {
        // 绘制X坐标
        mTextPaint.setTextSize(mXAxisFontSize);
        mTextPaint.setColor(mXAxisFontColor);
        for (int i = 0; i < mXAxisData.size() && i < mXAxis.size(); ++i)
        {
            String text = mXAxisData.get(i);
            canvas.drawText(text, mXAxis.get(i) - getTextWidth(mTextPaint, text) * 0.5f, getContentBottom() + mXAxisSpace, mTextPaint);
            if (DEBUG)
            {
                canvas.drawLine(mXAxis.get(i), mO.y, mXAxis.get(i), getContentRight(), mPaint);
            }
        }

        // 绘制Y坐标
        mTextPaint.setTextSize(mYAxisFontSize);
        mTextPaint.setColor(mYAxisFontColor);
        ArrayList<Float> yAxis = getYAxis();
        for (int i = 0; i < mYAxisData.size() && i < yAxis.size(); ++i)
        {
            canvas.drawText(mYAxisData.get(i), mO.x - mTextWidth - mLineSize - mYAxisSpace, yAxis.get(i) - mTextHeight * 0.5f, mTextPaint);
            if (DEBUG)
            {
                canvas.drawLine(mO.x - mLineSize - mYAxisSpace, yAxis.get(i), getContentRight(), yAxis.get(i), mPaint);
            }
        }

        if (DEBUG)
        {
            canvas.drawLine(mO.x, mO.y, getContentRight(), mO.y, mPaint);
            canvas.drawLine(mO.x, mO.y, mO.x, getContentTop(), mPaint);

            mPaint.setColor(Color.CYAN);
            canvas.drawRect(getPaddingLeft(), getPaddingTop(), getContentRight(), getContentBottom(), mPaint);
            mPaint.setColor(Color.BLACK);
            canvas.drawRect(mO.x - 5, mO.y - 5, mO.x + 5, mO.y + 5, mPaint);
        }
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = 0;
        int paddingH = paddingLeft + paddingRight;
        int paddingV = paddingTop + paddingBottom;

        if (heightMode == MeasureSpec.EXACTLY)
        {
            heightSize = MeasureSpec.getSize(heightMeasureSpec);
        } else
        {
            int desired = (int) (200 * getResources().getDisplayMetrics().density + 0.5f);

            heightSize = desired - paddingV;
            if (heightMode == MeasureSpec.AT_MOST)
            {
                heightSize = Math.min(desired, heightSize - paddingV);
            }
        }

        int width = widthSize - paddingLeft - paddingRight;
        int height = heightSize - paddingV;

        mContentWidth = width;
        mContentHeight = height;
        mTextWidth = getMaxTextWidth();
        mTextHeight = getTextHeight(mTextPaint);
        mO.set(paddingLeft + mTextWidth, getContentBottom() - Math.abs(mTextHeight) - mLineSize * 2f);
        setMeasuredDimension(widthSize, heightSize);
    }
    /**
     * 获取相对于原点的X坐标，也就是映射到坐标轴的坐标
     *
     * @param x
     * @return
     */
    protected float getOriginX(float x)
    {
        float v = (getContentRight() - mO.x - mXExtra) / 800;
        return x;
    }

    /**
     * 获取相对于原点的Y坐标，也就是映射到坐标轴的坐标
     *
     * @param y    需要转换的Y
     * @param min  实际数据最小值
     * @param yMax 计算出来Y轴的最大值
     * @param yMin 计算出来Y轴的最小值
     * @return
     */
    protected float getOriginY(float y, float max, float min, float yMax, float yMin)
    {
        y = (y - yMin) * ((max - min) / (yMax - yMin));
        float v = (mO.y - getContentTop() - mYExtra) / (max - min);
        return mO.y - y * v;
    }

    /**
     * 获取贝塞尔曲线的控制点
     *
     * @param linePoint 经过贝塞尔曲线的所有点
     * @param index     第index个点
     * @return 如果要让曲线经过index点，贝塞尔曲线的两个控制点。point[0]代表A点，point[1]代表B点
     */
    protected PointF[] getCtrlPoint(List<PointF> linePoint, int index)
    {
        float a = 0.18f;
        float b = 0.18f;
        int mStart = index - 1 <= 0 ? 0 : index - 1;
        float ax = linePoint.get(index).x + (linePoint.get(index + 1).x - linePoint.get(mStart).x) * a;
        float ay = linePoint.get(index).y + (linePoint.get(index + 1).y - linePoint.get(mStart).y) * a;
        int mEnd = index + 2 >= linePoint.size() ? linePoint.size() - 1 : index + 2;
        float bx = linePoint.get(index + 1).x - (linePoint.get(mEnd).x - linePoint.get(index).x) * b;
        float by = linePoint.get(index + 1).y - (linePoint.get(mEnd).y - linePoint.get(index).y) * b;
        PointF[] result = new PointF[2];
        result[0] = new PointF(ax, ay);
        result[1] = new PointF(bx, by);
        return result;
    }

    public ArrayList<Float> getXAxis()
    {
        if (mXAxis.isEmpty())
        {
            calculateXAxis();
        }
        return mXAxis;
    }

    public ArrayList<String> getXAxisData()
    {
        return mXAxisData;
    }

    public ArrayList<Float> getYAxis()
    {
        if (mYAxis.isEmpty())
        {
            calculateYAxis();
        }
        return mYAxis;
    }

    public ArrayList<String> getYAxisData()
    {
        return mYAxisData;
    }

    public float getTextWidth()
    {
        return mTextWidth;
    }

    public float getTextHeight()
    {
        return mTextHeight;
    }

    public PointF getO()
    {
        return mO;
    }

    /**
     * Y轴的数据基线
     */
    private float mYDataBaseLine = 0;
    private float mContentWidth;
    private float mContentHeight;

    /**
     * 返回字体高度
     *
     * @param paint
     * @return
     */
    private float getTextHeight(TextPaint paint)
    {
        return paint.descent() + paint.ascent();
    }

    /**
     * 获取文字的宽度
     *
     * @param paint
     * @param text
     * @return
     */
    private float getTextWidth(TextPaint paint, String text)
    {
        return paint.measureText(text);
    }

    public float getContentBottom()
    {
        return mContentHeight + getContentTop();
    }

    public float getContentLeft()
    {
        return getPaddingLeft();
    }

    public float getContentRight()
    {
        return mContentWidth + getContentLeft();
    }

    public float getContentTop()
    {
        return getPaddingTop();
    }
}